<template>
<div class="vue-box">
  <!-- 对话内容-->
  <div class="history">
    <div v-for="(item, index) in history" :key="index" class="history_q_a">
      <div class="history_q">
        <img src="@/assets/bg/logo.png">
        <vue-markdown :source="item.q"></vue-markdown>
      </div>
      <div class="history_a">
        <vue-markdown :source="item.a"></vue-markdown><img src="@/assets/bg/logo.png">
      </div>
    </div>
  </div>

  <!--  输入内容 -->
  <div class="request">
    <el-input type="textarea" autosize :disabled="socketStatus !== 'init'" v-model="m.q" placeholder="请输入你的问题" maxlength="500" show-word-limit />
    <div class="opr">
      <el-button type="primary" :disabled="socketStatus !== 'init'" @click="qa">{{ btnState[socketStatus]
          }}</el-button>
      <el-button type="info" @click="clearHistory">清空历史</el-button>
    </div>
  </div>
</div>
</template>

<script>
import sa from '@/sa-frame/sa';
import CryptoJS from 'crypto-js'
import VConsole from 'vconsole'
import VueMarkdown from 'vue-markdown'
// 动态获取
var vConsole = new VConsole()
export default {
  name: 'i-chat',
  props: {
    param: Object
  },
  data() {
    return {
      // 参数
      m: this.createModel(),
      // 用户名
      uid: sa.$sys.getCurUser().id,
      // 字典
      dims: this.param.dims,
      // 讯飞控制台获取
      appId: this.param.appId,
      // 讯飞控制台获取
      apiSecret: this.param.apiSecret,
      // 讯飞控制台获取
      apiKey: this.param.apiKey,
      // 扩展参数
      extra: {},
      httpUrl: new URL(this.param.url),
      btnState: {
        init: '立即提问',
        ttsing: '回答中...'
      },
      socketStatus: 'init',
      // 历史问题及答案
      history: [],
    }
  },
  components: {
    VueMarkdown
  },
  created: function () {
    // 转换参数
    let extraFields = JSON.parse(this.param.extraFields)
    // 组装数据
    if (extraFields) {
      for (var filed of extraFields) {
        let val = filed.val
        // 校验是否数字
        if (sa.isNumber(val)) {
          val = Number(val)
        }
        this.extra[filed.key] = val
      }
    }
  },
  methods: {
    createModel() {
      return {
        q: null,
        a: null,
      }
    },
    // 发送问题
    qa() {
      if (this.m.q) {
        this.history.push({
          q: this.m.q,
          a: ''
        })
        this.start()
      } else {
        sa.alert('请输入提问内容！')
      }
    },
    // 发送问题
    clearHistory() {
      this.history = []
      this.m = this.createModel()
    },
    //-----------socket --------------------

    getWebsocketUrl() {
      // 动态获取domain信息
      return new Promise((resolve, reject) => {
        var url = 'wss://' + this.httpUrl.host + this.httpUrl.pathname
        var host = location.host
        var date = new Date().toGMTString()
        var algorithm = 'hmac-sha256'
        var headers = 'host date request-line'
        var signatureOrigin = `host: ${host}\ndate: ${date}\nGET ${this.httpUrl.pathname} HTTP/1.1`
        var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, this.apiSecret)
        var signature = CryptoJS.enc.Base64.stringify(signatureSha)
        var authorizationOrigin = `api_key="${this.apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`
        var authorization = btoa(authorizationOrigin)
        url = `${url}?authorization=${authorization}&date=${date}&host=${host}`
        resolve(url)
      })
    },

    // 启动
    start() {
      this.connectWebSocket()
    },
    // 变更状态
    setStatus(status) {
      this.socketStatus = status
    },

    // 连接websocket
    connectWebSocket() {
      this.setStatus('ttsing')
      return this.getWebsocketUrl().then(url => {
        let ttsWS
        if ('WebSocket' in window) {
          ttsWS = new WebSocket(url)
        } else if ('MozWebSocket' in window) {
          ttsWS = new MozWebSocket(url)
        } else {
          sa.alert('该浏览器暂不支持WebSocket')
          return
        }
        this.ttsWS = ttsWS
        ttsWS.onopen = e => {
          this.webSocketSend()
        }
        ttsWS.onmessage = e => {
          this.result(e.data)
        }
        ttsWS.onerror = e => {
          clearTimeout(this.playTimeout)
          this.setStatus('init')
          sa.alert("AI · 问答 出错了！")
        }
        ttsWS.onclose = e => {
          console.log(e)
        }
      })
    },

    // websocket发送数据
    webSocketSend() {
      var params = {
        "header": {
          "app_id": this.appId,
          "uid": this.uid
        },
        "parameter": {
          "chat": {
            "domain": this.extra['domain'],
            "temperature": this.extra['temperature'],
            "max_tokens": this.extra['maxTokens'],
            "top_k": this.extra['topK'],
            "show_ref_label": Boolean(parseInt(this.extra['showRefLabel']))
          }
        },
        "payload": {
          "message": {
            "text": [{
                "role": this.extra['role'],
                "content": this.extra['roleDesc'] + ',目标任务,' + this.extra['targetTask'] + ',需求说明,' + this.extra['requirements']
              },
              {
                "role": "user",
                "content": this.history[this.history.length - 1].q
              }
            ]
          }
        }
      }
      this.ttsWS.send(JSON.stringify(params))
    },

    // websocket接收数据的处理
    result(resultData) {
      let jsonData = JSON.parse(resultData)
      let choices = jsonData.payload.choices
      if (choices) {
        let textArr = choices.text
        let anwser = this.history[this.history.length - 1].a
        for (let t of textArr) {
          anwser = anwser + t.content
          this.history[this.history.length - 1].a = anwser
        }
        // 提问失败
        if (jsonData.header.code !== 0) {
          alert(`提问失败: ${jsonData.header.code}:${jsonData.header.message}`)
          return
        }
        // 回答结束
        if (jsonData.header.code === 0) {
          if (jsonData.header.status === 2) {
            this.ttsWS.close()
            this.setStatus('init')
            this.m = this.createModel()
          }
        }
      }
    }
  },
}
</script>

<style scoped>
.vue-box {
  padding: 5px;
}

.history {
  height: 400px;
  border-radius: 5px;
  margin-bottom: 10px;
  padding: 10px;
  overflow: auto;

  .history_q_a {
    padding: 5px;

    .history_q {
      display: flex;
      justify-content: flex-start;
      align-items: center;
      margin-right: 40px;

      img {
        height: 20px;
        width: 20px;
        margin-right: 10px;
      }
    }

    .history_a {
      display: flex;
      justify-content: flex-end;
      align-items: end;
      margin-top: 10px;
      margin-bottom: 10px;
      margin-left: 40px;

      img {
        height: 20px;
        width: 20px;
        margin-left: 10px;
      }
    }
  }
}

.request {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 1px;
  border-radius: 5px;

  .opr {
    padding: 5px;
  }
}
</style>
